/**
 * Created on 20/04/2008
 * 
 */
package com.apbetioli.mapr.place.entity;

import com.apbetioli.mapr.place.control.geocoding.GeocoderClient;
import com.apbetioli.mapr.place.control.kml.KMLGenerator;
import com.apbetioli.mapr.place.exception.GeocodingException;
import com.apbetioli.mapr.place.exception.NullGeoPointException;
import com.apbetioli.mapr.place.schema.CtPlace;
import com.apbetioli.mapr.project.entity.Project;
import com.apbetioli.kml.schema.CtPlacemark;
import com.apbetioli.kml.schema.CtPoint;
import com.apbetioli.kml.schema.ObjectFactory;
import com.apbetioli.mapr.place.control.flickr.FlickrPhotoLocator;
import com.apbetioli.mapr.util.properties.PropertiesLoaderImpl;
import java.io.IOException;
import java.io.Serializable;
import java.net.UnknownHostException;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.JAXBException;

/**
 * Persistent entity class for places.
 * 
 * @author Alexandre Parra Betioli
 */
@Entity
@Table(name = "PLACE")
@NamedQueries({
@NamedQuery(name = "Place.listAll", query = "SELECT p FROM Place p ORDER BY p.name ASC")
})
public class Place extends CtPlace implements Serializable {

    /*---------------------------------------------*/
    // Attributes
    /*---------------------------------------------*/

    private Project project;

    /*---------------------------------------------*/
    // Columns
    /*---------------------------------------------*/
    @Id
    @Column(name = "NAME")
    @Override
    public String getName() {
        return super.getName();
    }

    @Embedded
    public Address getAddress() {
        if (super.getAddress() == null) {
            return null;
        }

        Address a = new Address();
        a.parse(super.getAddress());
        return a;
    }

    @Embedded
    public GeoPoint getGeoPoint() {
        if (super.getGeoPoint() == null) {
            return null;
        }

        GeoPoint g = new GeoPoint();
        g.parse(super.getGeoPoint());
        return g;
    }

    @Column(name = "NUMBER_OF_TREES")
    @Override
    public int getNumberOfTrees() {
        return super.getNumberOfTrees();
    }

    @Column(name = "PLANTED")
    @Override
    public boolean isPlanted() {
        return super.isPlanted();
    }

    @ManyToOne(targetEntity=Project.class)
    @JoinColumn(name = "PROJECT", nullable = false)
    public Project getProject() {
        return project;
    }

    /*---------------------------------------------*/
    // Setters
    /*---------------------------------------------*/
    public void setAddress(Address value) {
        super.setAddress(value);
    }

    public void setGeoPoint(GeoPoint value) {
        super.setGeoPoint(value);
    }

    public void setPlanted(boolean planted) {
        super.setPlanted(planted);
    }

    public void setProject(Project project) {
        this.project = project;
    }

    /*---------------------------------------------*/
    //Methods
    /*---------------------------------------------*/
    public void parse( final CtPlace ctPlace ) {

        this.setName(ctPlace.getName());
        this.setNumberOfTrees(ctPlace.getNumberOfTrees());
        this.setPlanted(ctPlace.isPlanted());

        Address a = new Address();
        a.parse(ctPlace.getAddress());

        this.setAddress(a);


        GeoPoint gp = null;

        if (ctPlace.getGeoPoint() != null) {
            gp = new GeoPoint();
            gp.parse(ctPlace.getGeoPoint());
        }

        this.setGeoPoint(gp);
    }

    public void geocode() throws IOException, JAXBException, GeocodingException, UnknownHostException {

        if ((this.getGeoPoint() == null) && (this.getAddress() != null)) {
            GeocoderClient gc = new GeocoderClient();
            this.setGeoPoint(gc.transform(this.getAddress()));
        }
    }

    public CtPlacemark toPlacemark() throws NullGeoPointException {

        if (this.getGeoPoint() == null) {
            throw new NullGeoPointException();
        }

        String imageUrl = "";

        if (this.getProject().getFlickrData() != null) {

            FlickrPhotoLocator fpl = new FlickrPhotoLocator(
                    PropertiesLoaderImpl.getValue("config.properties", "flickr.api.key"),
                    this.getProject().getFlickrData().getUserId().trim(),
                    this.getProject().getFlickrData().getPhotosetId().trim());

            imageUrl = fpl.getMediumImageUrl(this.getGeoPoint().getLatitude(), this.getGeoPoint().getLongitude());
        }

        ObjectFactory of = new ObjectFactory();
        CtPlacemark placemark = of.createCtPlacemark();
        CtPoint point = of.createCtPoint();

        placemark.setName(this.getName());
        placemark.setDescription(
                this.getAddress().toHtml() +
                PropertiesLoaderImpl.getValue("messages.properties", "place.kml.placemark") +
                ": <b>" + this.getNumberOfTrees() + "</b><br><br><div align=\"center\">" +
                imageUrl + "</div>");

        point.getCoordinates().add(Double.toString(this.getGeoPoint().getLongitude()));
        point.getCoordinates().add(",");
        point.getCoordinates().add(Double.toString(this.getGeoPoint().getLatitude()));

        placemark.setPoint(point);

        if (!this.isPlanted()) {
            placemark.setStyleUrl("#" + KMLGenerator.STYLE_ID_FUTURE);
        } else {
            placemark.setStyleUrl("#" + KMLGenerator.STYLE_ID_PLANTED);
        }

        return placemark;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (getName() != null ? getName().hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {

        if (!(object instanceof Place)) {
            return false;
        }

        Place other = (Place) object;

        if ((this.getName() == null && other.getName() != null) ||
                (this.getName() != null && !this.getName().equals(other.getName())) ||
                (this.getAddress() != other.getAddress()) ||
                (this.getGeoPoint() != other.getGeoPoint()) ||
                (this.getNumberOfTrees() != other.getNumberOfTrees()) ||
                (this.isPlanted() != other.isPlanted())) {
            return false;
        }

        return true;
    }

    @Override
    public String toString() {

        StringBuffer sb = new StringBuffer();
        sb.append("\nPlace: ");
        sb.append(this.getName());
        sb.append("\nAddress: ");
        sb.append(this.getAddress());

        if (this.getGeoPoint() != null) {
            sb.append("\nGeopoint: ");
            sb.append(this.getGeoPoint());
        }

        sb.append("\nNumber of ");
        sb.append(this.isPlanted() ? "planted " : "");
        sb.append("trees");
        sb.append(this.isPlanted() ? ": " : " to be planted: ");
        sb.append(this.getNumberOfTrees());

        sb.append("\nProject: ");
        sb.append(this.getProject().getName());

        return sb.toString();
    }

    public String toHtml() {
        return this.toString().replaceAll("\n", "<br>");
    }

    @Override
    public Place clone() {
        Place p = new Place();
        p.setName(this.getName());
        p.setAddress(this.getAddress().clone());
        p.setGeoPoint(this.getGeoPoint().clone());
        p.setNumberOfTrees(this.getNumberOfTrees());
        p.setPlanted(this.isPlanted());
        p.setProject(this.getProject().clone());
        return p;
    }
}
